/**
 * The GUI that is used to display game data.
 * @author Keilan Jackson
 * @version 1.0
 * 
 */
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

@SuppressWarnings("serial")
public class GameGUI extends JPanel {
	
	private String version = " (version 1.0)";
	private JFrame debugFrame;
	private JButton startButton;
	private JLabel scoreLabel, totalScoreLabel, expLabel, levelLabel, expToNextLabel, playsLabel; 
	private JLabel averageLabel, aExpLabel, aAverageLabel, highScoreLabel;
	private JLabel instructions, gameInfo;
	private JPanel masterContainer, infoPanel, gamePanel, welcomePanel, debugPanel;
	private JPanel info1, info2, info3, info4, info5, info6, info7;
	private JTextArea welcomeText;
	private boolean gameGoing = false, debugPanelVisible = false, isBreakTime;
	private ColoredBox panel;
	private int level, aLevel, score, totalScore, exp, aExp, expToNext, totalPlays, averageScore; 
	private int aAverageScore, highScore;
	private boolean gameIsOver, endColorGame;
	private Font globalFont, youngFont, oldFont;
	private ArrayList<JLabel> allLabels = new ArrayList<JLabel>();;
	private JCheckBox ageCheck;
	private int globalWidth, globalHeight, youngWidth, youngHeight, oldWidth, oldHeight;
	
	public GameGUI() {
		level = 1;
		totalScore = 0;
		exp = 0;
		expToNext = 2;
		
		youngWidth = 500;
		youngHeight = 300;
		oldWidth = 2*youngWidth;
		oldHeight = 2*youngHeight;
		globalWidth = youngWidth;
		globalHeight = youngHeight;
		
		youngFont = new Font(Font.SANS_SERIF, Font.BOLD, 12);
		oldFont = new Font(Font.SANS_SERIF, Font.BOLD, 24);
		globalFont = youngFont;
		
		masterContainer = new JPanel();
		masterContainer.setPreferredSize(new Dimension(globalWidth,globalHeight));
		masterContainer.setBackground(Color.black);
		masterContainer.setLayout(new BorderLayout());
		
		infoPanel = new JPanel();
		infoPanel.setPreferredSize(new Dimension ((int) (.4 * globalWidth), globalHeight));
		infoPanel.setLayout(new BoxLayout (infoPanel, BoxLayout.Y_AXIS));
		
		welcomePanel = new JPanel();
		welcomePanel.setLayout(new BoxLayout (welcomePanel, BoxLayout.Y_AXIS));
		welcomeText = new JTextArea(12,40);
		welcomeText.setLineWrap(true);
		welcomeText.setWrapStyleWord(true);
		welcomeText.setEditable(false);
		welcomeText.setText("Welcome to the ColorGame!" + version + "\n"+
							"*You will be shown a color for 3 seconds - memorize it!\n" +
							"*Click when you think your color comes up again\n" +
							"*You will be scored based on how close your color is\n" +
							"*Gain experience by doing well and go up in level\n" +
							"*Harder levels have more colors and faster transitions\n" +
							"*See how good you can do in 10 levels!\n" +
							"*New \"I'm Old\" option for those with bad eyesight\n" +
							"\nClick \"Start\" to begin!");
		welcomeText.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 18));
				
		scoreLabel = createJLabel("(+" + score + ")");
		scoreLabel.setForeground(Color.green);
		totalScoreLabel = createJLabel("Total Score: " + totalScore);
		expLabel = createJLabel("Experience: " + exp + "/");
		expToNextLabel = createJLabel("" + expToNext);
		aExpLabel = createJLabel("(+" + aExp + ")");
		aExpLabel.setForeground(Color.green);
		levelLabel = createJLabel("Level: " + level);
		playsLabel = createJLabel("Total Plays: " + totalPlays);
		averageLabel = createJLabel("Average score: " + averageScore);
		aAverageLabel = createJLabel("(+" + aAverageScore + ")");
		aAverageLabel.setForeground(Color.green);
		highScoreLabel = createJLabel("High Score: " + highScore);
		
		gameInfo = createJLabel("");
		instructions = createJLabel("Wait for the timer.");
		
		gamePanel = new JPanel();
		gamePanel.setPreferredSize(new Dimension((int)(.6 * globalWidth), globalHeight));
		gamePanel.setLayout(new BoxLayout(gamePanel, BoxLayout.Y_AXIS));
		
		startButton = new JButton("Start");
		startButton.addActionListener(new StartButtonListener());
		
		ageCheck = new JCheckBox("I'm OLD!");
		ageCheck.addItemListener(new AgeCheckListener());
		
		info1 = new JPanel();
		info1.setLayout (new BorderLayout());
		info1.add(totalScoreLabel, BorderLayout.WEST);
		info1.add(scoreLabel, BorderLayout.EAST);
		info2 = new JPanel();
		info2.setLayout (new BorderLayout());
		info2.add (expLabel, BorderLayout.WEST);
		info2.add (expToNextLabel, BorderLayout.CENTER);
		info2.add (aExpLabel, BorderLayout.EAST);
		info3 = new JPanel();
		info3.setLayout (new BorderLayout());
		info3.add (levelLabel, BorderLayout.WEST);
		//info3.add (aLevelLabel, BorderLayout.EAST);
		info4 = new JPanel();
		info4.setLayout (new BorderLayout());
		info4.add (playsLabel);
		info5 = new JPanel();
		info5.setLayout (new BorderLayout());
		info5.add (averageLabel, BorderLayout.WEST);
		info5.add (aAverageLabel, BorderLayout.EAST);
		info6 = new JPanel();
		info6.setLayout(new BorderLayout());
		info6.add (highScoreLabel, BorderLayout.WEST);
		info7 = new JPanel();
		info7.setLayout(new BorderLayout());
		info7.add(ageCheck, BorderLayout.WEST);
		
		//infoPanel.add (startButton);
		infoPanel.add (info1); //total and last score
		infoPanel.add (info2); //experience
		infoPanel.add (info3); //level
		infoPanel.add (info4); //plays
		infoPanel.add (info5); //average
		infoPanel.add (info6); //high score
		infoPanel.add (info7); //age check box
		
		welcomePanel.add (welcomeText);
		welcomePanel.add (startButton);
		
		masterContainer.add (welcomePanel, BorderLayout.CENTER);
		//masterContainer.add (infoPanel, BorderLayout.WEST);
		//masterContainer.add (gamePanel, BorderLayout.EAST);

		debugFrame = new JFrame("Debug Frame");
		addKeyListener (new DebugListener());
		setFocusable(true);
		add (masterContainer);
	}
	
	//add a typical instance of the game
	private void startGameInstance(int l) {
		totalPlays++;
		panel = new ColoredBox(l, globalFont, globalWidth);
		panel.addMouseListener(new GamePanelListener());
		debugPanel = panel.getDebugPanel();
		debugPanel.setVisible(true);
		debugFrame.add (debugPanel);
		debugFrame.setVisible(debugPanelVisible);
		gameIsOver = panel.gameIsOver;
		isBreakTime = false;
		gameInfo = panel.gameInfo;
		instructions = panel.instructions;
		gamePanel.add (gameInfo);
		gamePanel.add (panel);
		gamePanel.add (instructions);
		panel.setVisible(false);  //for some reason this makes it not delay the showing of the panel
		panel.setVisible(true);   //also, this must be done after panel is added...
	}
	//remove the instance of the game
	private void endGameInstance() {
		debugFrame.remove (debugPanel);
		gamePanel.remove (gameInfo);
		gamePanel.remove (panel);
		gamePanel.remove (instructions);
	}
	//sets the score, updates totalScore and the score labels
	private void setScore(int s){
		score = s;
		totalScore += s;
		int tempAverageScore = totalScore / totalPlays;
		aAverageScore = tempAverageScore - averageScore;
		averageScore = tempAverageScore;
		if(totalPlays == 1) {
			highScore = s;
		} else if(s > highScore) {
			highScore = s;
		}
			
		aExp = 0;
		if(0 < score && score <= 500)
			aExp += 0;
		if(500 < score && score <= 1000)
			aExp += 1;
		if(1000 < score && score <= 2000)
			aExp += 2;
		if(2000 < score && score <= 4000){
			aExp += 2;
			if(level > 2)
				aExp += 2;
		}
		if(4000 < score && score <= 8000){
			aExp += 4;
			if(level > 4)
				aExp += 4;
		}
		if(8000 < score && score <= 16000){
			aExp += 8;
			if(level > 6)
				aExp += 8;
		}
		if(16000 < score) {
			aExp += 16;
			if(level > 8)
				aExp += 16;
		}
		exp += aExp;
	}
	private JLabel createJLabel(String str) {
		JLabel label = new JLabel(str);
		label.setFont(globalFont);
		allLabels.add (label);
		return label;
	}
	
	private void setAllLabelsFont() {
		for(JLabel label: allLabels){
			label.setFont(globalFont);
		}
		ageCheck.setFont(globalFont);
		gameInfo.setFont(globalFont);
		instructions.setFont(globalFont);
	}
	
	private void setPanelSizes() {
		infoPanel.setPreferredSize(new Dimension((int)(.4*globalWidth), globalHeight));
		gamePanel.setPreferredSize(new Dimension((int)(.6*globalWidth), globalHeight));
		masterContainer.setPreferredSize(new Dimension(globalWidth,globalHeight));
		panel.setGlobalWidth(globalWidth);
		//retrieves the parent container and repacks it.
		Frame wtf = (java.awt.Frame)SwingUtilities.getAncestorOfClass(java.awt.Frame.class, this);
		wtf.pack();
	}
	
	//calculates level based on exp earned
	private void calcLevel(){
		aLevel = 0;
		if(exp >= expToNext){
			level++;
			expToNext *= 2;
			//exp = 0;
			aLevel = 1;
		}
		if(level > 10)
			endColorGame = true;
	}
	//itemlistener for checkbox agecheck
	private class AgeCheckListener implements ItemListener {
		public void itemStateChanged (ItemEvent event) {
			if(globalFont.equals(youngFont)){
				globalFont = oldFont;
				globalWidth = oldWidth;
				globalHeight = oldHeight;
			} else {
				globalFont = youngFont;
				globalWidth = youngWidth;
				globalHeight = youngHeight;
			}
			setAllLabelsFont();
			setPanelSizes();
		}
	}
	//Button listener for start button
	private class StartButtonListener implements ActionListener {
		public void actionPerformed (ActionEvent event) {
			if(!gameGoing){
				masterContainer.remove (welcomePanel);
				masterContainer.add (infoPanel, BorderLayout.WEST);
				masterContainer.add (gamePanel, BorderLayout.EAST);				
				startGameInstance(level);
				gameGoing = true;
				startButton.setFocusable(false);
				gamePanel.add (instructions);
			}
		}
	}
	//Key listener for debug mode
	private class DebugListener implements KeyListener {
		public void keyPressed(KeyEvent event) {
			switch (event.getKeyCode()) {
				case KeyEvent.VK_BACK_QUOTE:
					debugFrame.setVisible(!debugPanelVisible);
					debugPanelVisible = !debugPanelVisible;
					break;
			}
			//repaint();
		}
		public void keyReleased(KeyEvent event) {		
		}
		public void keyTyped(KeyEvent event) {
		}
	}
	
	//Mouse listener
	protected class GamePanelListener implements MouseListener {
		public void mousePressed(MouseEvent event) {
		}
		public void mouseClicked(MouseEvent event) {
			if(!endColorGame) {
				gameIsOver = panel.gameIsOver;
				if(!gameIsOver && panel.getGameTimerStatus()) {
					panel.endGame();
					updateInfoPanel();
					isBreakTime = false;
					repaint();
				}
				if(gameIsOver && !isBreakTime) {
					isBreakTime = true;
					gameGoing = false;	
					repaint();
				}
				if(gameIsOver && !gameGoing && isBreakTime) {
					endGameInstance();
					startGameInstance(level);
					gameGoing = true;
					repaint();
				}
			} else {
				instructions.setText("GAME OVER");
			}

		}
		public void mouseReleased(MouseEvent event) {	
		}
		public void mouseEntered(MouseEvent event) {	
		}
		public void mouseExited(MouseEvent event) {
		}
	}
	//called after the game is ended... gets current score, calculates level, updates the labels
	private void updateInfoPanel(){
		setScore(panel.getScore());
		calcLevel();
		scoreLabel.setText("(+" + score + ")");
		totalScoreLabel.setText("Total Score: " + totalScore);
		expLabel.setText("Experience: " + exp + "/");
		expToNextLabel.setText("" + expToNext);
		aExpLabel.setText("(+" + aExp + ")");
		levelLabel.setText("Level: " + level);
		if(aLevel == 1)
			levelLabel.setForeground(Color.green);
		else
			levelLabel.setForeground(Color.black);
		playsLabel.setText("Total Plays: " + totalPlays);
		averageLabel.setText("Average score: " + averageScore);
		if(aAverageScore >= 0){
			aAverageLabel.setText("(+" + aAverageScore + ")");
			aAverageLabel.setForeground(Color.green);
		} else {
			aAverageLabel.setText("(" + aAverageScore + ")");
			aAverageLabel.setForeground(Color.red);
		}
		highScoreLabel.setText("High Score: " + highScore);
		if(highScore == score)
			highScoreLabel.setForeground(Color.green);
		else
			highScoreLabel.setForeground(Color.black);
	}
}

